package function;
import java.util.ArrayList;

import multiarray.MultiArray;
import ccpv.Person;
import ccpv.RunTimeSettings;

public class SimpleFunc  {

	double[] sum_pi_squared_i;
	double[] sum_pi_minus_i;
	double[] sum_pi_i;
	double[] pi_i;
	double lambda = 0.5;
	double phi = 0.2;
	double precision = 0.0001;
	int dims = 0;
	int num_coalitions = 0;
	
	
	public double f(double[][] thetas, int i) {
	  double result = 0;
	  result = result + (1- lambda);
	  result = result + -1*phi*pi_i[i];
	  result = result + pi_i[i]*lambda*((phi*thetas[0][i]*pi_i[i])+(sum_pi_minus_i[i]))/(thetaPi_sum(thetas[0], pi_i));
	  result = result * sum_pi_squared_i[i];
	  return result;
	}

	
	public double jacobian(double[][] thetas, int i, int j, int unused) {
		
		double pithetasum = thetaPi_sum(thetas[0], pi_i);
		double result = 0;
		if (i==j) {
		  result = result + -1*sum_pi_squared_i[i]*phi;
		  double numerator = (phi*thetas[0][i]*pi_i[i]+sum_pi_minus_i[i]);
		  result = result + sum_pi_squared_i[i]*lambda*(numerator)/(pithetasum);
		  result = result + pi_i[i]*sum_pi_squared_i[i]*lambda*(phi*pi_i[i]*pithetasum-(numerator)*pi_i[i])/(pithetasum*pithetasum);
		} else {
			result = -1*(pi_i[i]*sum_pi_squared_i[i]*lambda)*(phi*thetas[0][i]*pi_i[i]+sum_pi_minus_i[i])*(thetas[0][j]*pi_i[j])/(pithetasum*pithetasum); 
		}
		return result;
	}

	
	public void setCoalitions(ArrayList<ArrayList<int[]>> coalitions, MultiArray<Person> population) {
		dims = coalitions.get(0).get(0).length;
		num_coalitions = coalitions.size(); 
		sum_pi_squared_i = new double[coalitions.size()];
		pi_i = new double[coalitions.size()];
		sum_pi_minus_i = new double[coalitions.size()];
		double total_power = 0;
		Person temp_person;
		
		System.out.println("Num coalitions:" + coalitions.size());
		System.out.println("Coalitions:" + coalitions.size());
		for (int i = 0; i < coalitions.size(); i++) {
			for (int j = 0; j<coalitions.get(i).size(); j++) {
				System.out.print("  ");
				for (int k = 0; k<coalitions.get(0).get(0).length; k++) {
					System.out.print(coalitions.get(i).get(j)[k]);
				}
				System.out.println();
			}
			System.out.println();
		}
		
/*		System.out.println("HashMap:");
		System.out.println("Key  Power Qty");
for (int[] key : population.keySet()) {
	for (int k = 0; k<coalitions.get(0).get(0).length; k++) {
		System.out.print(key[k]);
	}
	System.out.print("   " + population.get(key).getPower()  + "  " + population.get(key).getQty());
	System.out.println();
}*/
		
		int[] tempChar = new int[3];
		double tempPower = 0;
		for (int i = 0; i<coalitions.size(); i++) {
			for (int j = 0; j<coalitions.get(i).size(); j++) {
				tempChar = coalitions.get(i).get(j);
				System.out.print("Getting person ");
				for (int k = 0; k<coalitions.get(i).get(j).length; k++) {
					System.out.print(coalitions.get(i).get(j)[k]);
				}
				System.out.println();
				temp_person = population.getElementAtIndex(tempChar); 
				System.out.println("  Power: " +temp_person.getPower() + "  Population: " + temp_person.getQty());
				tempPower = temp_person.getPower()*temp_person.getQty();
				pi_i[i] = pi_i[i] + tempPower;
				total_power = total_power + tempPower; 
				sum_pi_squared_i[i] = sum_pi_squared_i[i] + tempPower*tempPower; 
			}
		}
		
		for (int i = 0; i<pi_i.length; i++) {
			sum_pi_minus_i[i] = total_power - pi_i[i];
		}
		
	}

	/*
	public void setCoalitions(ArrayList<ArrayList<int[]>> coalitions, HashMap<int[],Person> population) {
		sum_pi_squared_i = new double[coalitions.size()];
		pi_i = new double[coalitions.size()];
		sum_pi_minus_i = new double[coalitions.size()];
		double total_power = 0;
		Person temp_person;
		
		System.out.println("Num coalitions:" + coalitions.size());
		System.out.println("Coalitions:" + coalitions.size());
		for (int i = 0; i < coalitions.size(); i++) {
			for (int j = 0; j<coalitions.get(i).size(); j++) {
				System.out.print("  ");
				for (int k = 0; k<coalitions.get(0).get(0).length; k++) {
					System.out.print(coalitions.get(i).get(j)[k]);
				}
				System.out.println();
			}
			System.out.println();
		}
		
		System.out.println("HashMap:");
		System.out.println("Key  Power Qty");
for (int[] key : population.keySet()) {
	for (int k = 0; k<coalitions.get(0).get(0).length; k++) {
		System.out.print(key[k]);
	}
	System.out.print("   " + population.get(key).getPower()  + "  " + population.get(key).getQty());
	System.out.println();
}
		
		int[] tempChar = new int[3];
		double tempPower = 0;
		for (int i = 0; i<coalitions.size(); i++) {
			for (int j = 0; j<coalitions.get(i).size(); j++) {
				tempChar = coalitions.get(i).get(j);
				System.out.print("Getting person ");
				for (int k = 0; k<coalitions.get(i).get(j).length; k++) {
					System.out.print(coalitions.get(i).get(j)[k]);
				}
				System.out.println();

				if (!population.containsKey(tempChar)) System.out.println("Key not found.");
				population.put(tempChar, new Person(tempChar,0,0,0));
				temp_person = population.get(tempChar); 
				tempPower = temp_person.getPower()*temp_person.getQty();
				pi_i[i] = pi_i[i] + tempPower;
				total_power = total_power + tempPower; 
				sum_pi_squared_i[i] = sum_pi_squared_i[i] + tempPower*tempPower; 
			}
		}
		
		for (int i = 0; i<pi_i.length; i++) {
			sum_pi_minus_i[i] = total_power - pi_i[i];
		}
		
	}*/
	
	/**
	 * Initializes the constants in the function, stored in runtimesettings.
	 * @param rt
	 */
	public void initializeConstants(RunTimeSettings rt) {
		lambda = rt.getLambda();
		phi = rt.getPhi();	
		precision = rt.getPrecision();
	}
	
	/*
	public void initializeFunction(ArrayList<ArrayList<int[]>> coalitions, RunTimeSettings rt, int year) {
		
		sum_pi_squared_i = new double[coalitions.size()];
		pi_i = new double[coalitions.size()];
		sum_pi_minus_i = new double[coalitions.size()];
		double total_power = 0;
		
		int[] tempChar;
		double tempPower = 0;
		for (int i = 0; i<coalitions.size(); i++) {
			for (int j = 0; j<coalitions.get(i).size(); j++) {
				tempChar = coalitions.get(i).get(j);
				tempPower = rt.getValue(year, tempChar, 0)*rt.getPopulation(year, tempChar);
				pi_i[i] = pi_i[i] + tempPower;
				total_power = total_power + tempPower; 
				sum_pi_squared_i[i] = sum_pi_squared_i[i] + tempPower*tempPower; 
			}
		}
		
		for (int i = 0; i<pi_i.length; i++) {
			sum_pi_minus_i[i] = total_power - pi_i[i];
		}
		
	}*/
	
	private static double thetaPi_sum(double[] thetas, double[] pis) {
		return dotProduct(thetas,pis);
	}
	
	private static double dotProduct(double[] v1, double[] v2) {
		double result = 0;
		assert(v1.length == v2.length);
		for(int i =0; i<v1.length; i++) {
			result = result + v1[i]*v2[i];
		}
		return result;
	}


	public int getNumCoalitions() {
		return num_coalitions;
	}
	
}
